/////////////////////////////////////////////////////////////////////////////////
//
//  QAFDebug critical error log
//
//  Copyright (c) 2000-2004
//  Andrew Schetinin
//
//  This software is provided "as is" without express or implied warranty, 
//  and with no claim as to its suitability for any purpose.
//
//  Permission to use or copy this software for any purpose is hereby granted 
//  without fee, provided the above notices are retained on all copies.
//  Permission to modify the code and to distribute modified code is granted,
//  provided the above notices are retained, and a notice that the code was
//  modified is included with the above copyright notice.
//
//  This software accompanies the article "Code that debugs itself"
//  located at http://www.codeproject.com/debug/qafdebug.asp
//
//  You are welcomed to report bugs, send comments and post code modifications 
//  to aschetinin@hotmail.com 
//
/////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
/// @file QSockErr.h
/// @brief Part of QAFDebug facility for reporting WinSock errors.
//////////////////////////////////////////////////////////////////////////

#ifndef _QSOCKERR_29347284234_H_
#define _QSOCKERR_29347284234_H_

// The error constants are taken from WinSock2.h but I think they are 
// similar to ones defined in WinSock.h. 
// Errors are usually returned by WSAGetLastError()
#ifdef _WINSOCKAPI_

#include <string>

#include "QAFDebug.h"

/// Macro that reports about a socket error if it happens, 
/// it reports also about the source code position.
/// The macro returns the same error code that it got as input.
#ifndef QAF_DISABLED
	#define Q_SOCKET_ERROR( iSocketError ) QAFDebug::ReportSocketErrorImpl( (iSocketError), _T(__FILE__), __LINE__ )
#else 
	#define Q_SOCKET_ERROR( iSocketError ) (iSocketError)
#endif

// namespace QAFDebug
namespace QAFDebug
{

/// Returns the error message by the error code.
/// An empty string is returned in case no error occured.
#ifdef _UNICODE
inline int GetSocketErrorMessage( const int iSocketError, std::wstring & szRet )
#else
inline int GetSocketErrorMessage( const int iSocketError, std::string & szRet )
#endif
{
	szRet = _T(""); // empty the result string
	if( 0 == iSocketError )
		return iSocketError;
	switch( iSocketError )
	{
		case WSAEINTR:
			szRet = ( _T("WSAEINTR: Interrupted function call") );
			break;
		case WSAEACCES:
			szRet = ( _T("WSAEACCES: Permission denied") );
			break;
		case WSAEFAULT:
			szRet = ( _T("WSAEFAULT: Invalid pointer address") );
			break;
		case WSAEINVAL:
			szRet = ( _T("WSAEINVAL: Invalid argument") );
			break;
		case WSAEMFILE:
			szRet = ( _T("WSAEMFILE: Too many open sockets") );
			break;
		case WSAEWOULDBLOCK:
			szRet = ( _T("WSAEWOULDBLOCK: Resource temporarily unavailable") );
			break;
		case WSAEINPROGRESS:
			szRet = ( _T("WSAEINPROGRESS: Operation now in progress") );
			break;
		case WSAEALREADY:
			szRet = ( _T("WSAEALREADY: Operation already in progress") );
			break;
		case WSAENOTSOCK:
			szRet = ( _T("WSAENOTSOCK: Socket operation on nonsocket") );
			break;
		case WSAEDESTADDRREQ:
			szRet = ( _T("WSAEDESTADDRREQ: Destination address required") );
			break;
		case WSAEMSGSIZE:
			szRet = ( _T("WSAEMSGSIZE: Message too long") );
			break;
		case WSAEPROTOTYPE:
			szRet = ( _T("WSAEPROTOTYPE: Protocol wrong type for socket") );
			break;
		case WSAENOPROTOOPT:
			szRet = ( _T("WSAENOPROTOOPT: Bad protocol option") );
			break;
		case WSAEPROTONOSUPPORT:
			szRet = ( _T("WSAEPROTONOSUPPORT: Protocol not supported") );
			break;
		case WSAESOCKTNOSUPPORT:
			szRet = ( _T("WSAESOCKTNOSUPPORT: Socket type not supported") );
			break;
		case WSAEOPNOTSUPP:
			szRet = ( _T("WSAEOPNOTSUPP: Operation not supported") );
			break;
		case WSAEPFNOSUPPORT:
			szRet = ( _T("WSAEPFNOSUPPORT: Protocol family not supported") );
			break;
		case WSAEAFNOSUPPORT:
			szRet = ( _T("WSAEAFNOSUPPORT: Address family not supported by protocol family") );
			break;
		case WSAEADDRINUSE:
			szRet = ( _T("WSAEADDRINUSE: Address already in use") );
			break;
		case WSAEADDRNOTAVAIL:
			szRet = ( _T("WSAEADDRNOTAVAIL: Cannot assign requested address") );
			break;
		case WSAENETDOWN:
			szRet = ( _T("WSAENETDOWN: Network is down") );
			break;
		case WSAENETUNREACH:
			szRet = ( _T("WSAENETUNREACH: Network is unreachable") );
			break;
		case WSAENETRESET:
			szRet = ( _T("WSAENETRESET: Network dropped connection on reset") );
			break;
		case WSAECONNABORTED:
			szRet = ( _T("WSAECONNABORTED: Software caused connection abort") );
			break;
		case WSAECONNRESET:
			szRet = ( _T("WSAECONNRESET: Connection reset by peer") );
			break;
		case WSAENOBUFS:
			szRet = ( _T("WSAENOBUFS: No buffer space available") );
			break;
		case WSAEISCONN:
			szRet = ( _T("WSAEISCONN: Socket is already connected") );
			break;
		case WSAENOTCONN:
			szRet = ( _T("WSAENOTCONN: Socket is not connected") );
			break;
		case WSAESHUTDOWN:
			szRet = ( _T("WSAESHUTDOWN: Cannot send after socket shutdown") );
			break;
		case WSAETIMEDOUT:
			szRet = ( _T("WSAETIMEDOUT: Connection timed out") );
			break;
		case WSAECONNREFUSED:
			szRet = ( _T("WSAECONNREFUSED: Connection refused") );
			break;
		case WSAEHOSTDOWN:
			szRet = ( _T("WSAEHOSTDOWN: Host is down") );
			break;
		case WSAEHOSTUNREACH:
			szRet = ( _T("WSAEHOSTUNREACH: No route to host") );
			break;
		case WSAEPROCLIM:
			szRet = ( _T("WSAEPROCLIM: Too many processes") );
			break;
		case WSASYSNOTREADY:
			szRet = ( _T("WSASYSNOTREADY: Network subsystem is unavailable") );
			break;
		case WSAVERNOTSUPPORTED:
			szRet = ( _T("WSAVERNOTSUPPORTED: Winsock.dll version out of range") );
			break;
		case WSANOTINITIALISED:
			szRet = ( _T("WSANOTINITIALISED: Successful WSAStartup not yet performed") );
			break;
		case WSAEDISCON:
			szRet = ( _T("WSAEDISCON: Graceful shutdown in progress") );
			break;
		case WSATYPE_NOT_FOUND:
			szRet = ( _T("WSATYPE_NOT_FOUND: Class type not found") );
			break;
		case WSAHOST_NOT_FOUND:
			szRet = ( _T("WSAHOST_NOT_FOUND: Host not found") );
			break;
		case WSATRY_AGAIN:
			szRet = ( _T("WSATRY_AGAIN: Nonauthoritative host not found") );
			break;
		case WSANO_RECOVERY:
			szRet = ( _T("WSANO_RECOVERY: This is a nonrecoverable error") );
			break;
		case WSANO_DATA:
			szRet = ( _T("WSANO_DATA: Valid name, no data record of requested type") );
			break;
		case WSA_INVALID_HANDLE:
			szRet = ( _T("WSA_INVALID_HANDLE: Specified event object handle is invalid") );
			break;
		case WSA_INVALID_PARAMETER:
			szRet = ( _T("WSA_INVALID_PARAMETER: One or more parameters are invalid") );
			break;
		case WSA_IO_INCOMPLETE:
			szRet = ( _T("WSA_IO_INCOMPLETE: Overlapped I/O event object not in signaled state") );
			break;
		case WSA_IO_PENDING:
			szRet = ( _T("WSA_IO_PENDING: Overlapped operations will complete later") );
			break;
		case WSA_NOT_ENOUGH_MEMORY:
			szRet = ( _T("WSA_NOT_ENOUGH_MEMORY: Insufficient memory available") );
			break;
		case WSA_OPERATION_ABORTED:
			szRet = ( _T("WSA_OPERATION_ABORTED: Overlapped operation aborted") );
			break;
		/* Not defined even in .NET SDK
		case WSAINVALIDPROCTABLE:
			szRet = ( _T("WSAINVALIDPROCTABLE: Invalid procedure table from service provider") );
			break;
		case WSAINVALIDPROVIDER:
			szRet = ( _T("WSAINVALIDPROVIDER: Invalid service provider version number") );
			break;
		case WSAPROVIDERFAILEDINIT:
			szRet = ( _T("WSAPROVIDERFAILEDINIT: Unable to initialize a service provider") );
			break;
		*/
		case WSASYSCALLFAILURE:
			szRet = ( _T("WSASYSCALLFAILURE: System call failure") );
			break;
		default:
			TCHAR szBuf[40] = { 0 };
			_stprintf( szBuf, _T("%d: Unspecified socket error") );
			szRet = ( szBuf );
			break;
	}
	return iSocketError;
}

/// Returns the error message by the error code.
/// An empty string is returned in case no error occured.
#ifdef _UNICODE
inline std::wstring GetSocketErrorMessage( const int iSocketError )
#else
inline std::string GetSocketErrorMessage( const int iSocketError )
#endif
{
#ifdef _UNICODE
	std::wstring szError;
#else
	std::string szError;
#endif
	GetSocketErrorMessage( iSocketError, szError );
	if( szError.empty() )
		szError = _T("No error");
	return szError;
}

/// Internal function that report about socket error if it happens,
/// it reports also about the source code position.
/// The function returns the same error code that it got as input.
inline int ReportSocketErrorImpl( const int iSocketError, LPCTSTR const szFile, const int iLine )
{
	if( 0 == iSocketError )
		return 0;
#ifdef _UNICODE
	std::wstring szError;
#else
	std::string szError;
#endif
	// this call itself must return an error code
	Q_ASSERT( 0 != GetSocketErrorMessage( iSocketError, szError ) );
	Q_ASSERT( !szError.empty() );
	// report the error
	QAFDebug::OutputDebugStringEx( szFile, iLine, QAFDEBUG_ERROR_LOG, szError.c_str() );
	return iSocketError;
}

// namespace QAFDebug
};

#endif


#endif 

